/**
 * @filename Setup.java
 * @package top.h2v.cmpp[CMPP]
 * @description 读取配置文件
 * @author 胡正衛 
 * @date 2012-7-11 下午5:35:58
 * @version v0.1
 */
package com.github.cdisk.xtrans.core;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.github.cdisk.xtrans.connect.Connect;
import com.github.cdisk.xtrans.parser.ConfigFileParser;


/**
 * @author 胡正衛
 */
public class ConfigFile {
	
	private static final Logger LOGGER = Logger.getLogger(ConfigFile.class);
	
	/** 建立的数据库连接 */
	public List<Connect> connects = new ArrayList<Connect>();

	/** 所有元件 */
	public List<BaseComponent> components = new ArrayList<BaseComponent>();

	/** 准备执行的元件 */
	@JsonIgnore
	public List<BaseComponent> beginnings = new ArrayList<BaseComponent>();

	/** 执行时间点 */
	public String time;

	/** 执行间隔 */
	public String interval;

	/** 最后一次执行时间 */
	@JsonIgnore
	public Date lasttime;

	/** 文件物理路径 */
	@JsonIgnore
	public String file;


	public static void main(String[] args) throws Exception {
		ConfigFile config = ConfigFile.Read("E:\\eclipse_rcp\\xtrans\\text.xdt", null, false);
		config.components.add(new BaseComponent() {
			@Override
			public int execute(Map<String, Object> input) {
				return 0;
			}
		});
		config.components.add(new BaseComponent() {
			@Override
			public int execute(Map<String, Object> input) {
				return 0;
			}
		});
		config.save();
		System.out.println();
	}

	/**
	 * 读取配置文件
	 * @param config_file
	 * @param init
	 * @return
	 * @throws Exception
	 */
	public static ConfigFile Read(String config_file, GlobalVariables variables, boolean init) throws Exception {
		LOGGER.info("准备载入文件：" + config_file);
		ConfigFile configFile = ConfigFileParser.read(config_file);
		LOGGER.info("文件载入完成，准备初始化......");
		configFile.file = config_file;
		if (init) {
			configFile.init(variables);
			LOGGER.info("文件初始化完成......");
		}
		return configFile;
	}

	public ConfigFile() {}

	/**
	 * 初始化并装在各项参数，正式运行时需要调用，编辑时无需调用
	 * @param variables 
	 * @throws Exception 
	 * @throws ParserConfigurationException
	 */
	public void init(GlobalVariables variables) throws Exception {

		time = variables.replaceVariables(time);
		if (time != null && time.length() == 0) {
			time = null; // 配置的可能是空串，直接转换为null，方便后续处理。
		}
		if (time != null && !time.matches("^([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d$")) {
			throw new SQLException("指定的[time]定时执行，时间定义不符合要求，请使用00:00:00的格式。");
		}
		interval = variables.replaceVariables(interval);
		if (interval != null && interval.length() == 0) {
			interval = null; // 配置的可能是空串，直接转换为null，方便后续处理。
		}
		if (interval != null && !interval.matches("^\\d+$")) {
			throw new SQLException("指定的[interval]间隔执行，间隔定义不符合要求，请使用纯数字如1000的格式。");
		}

		/* 初始化连接所需要的类 */
		for (int i = 0; i < connects.size(); i++) {
			connects.get(i).init(variables);
		}

		/* 组装SQL属性 */
		for (int i = 0; i < components.size(); i++) {
			components.get(i).build(this, variables);
		}

		/* 找到流程的根，即起点元件 */
		for (BaseComponent component : components) {
			List<BaseComponent> comps = findReferenceComponent(component);
			if (comps.size() == 0) { // 如果该组件没有被任何元件引用过，说明该元件是第一个执行的
				beginnings.add(component);
			}
		}

	}

	/**
	 * 查找引用过该元件的元件
	 * @param component 被引用的元件
	 * @return 引用过的元件集合
	 */
	private List<BaseComponent> findReferenceComponent(BaseComponent component) {
		List<BaseComponent> coms = new ArrayList<BaseComponent>();
		for (BaseComponent com : components) {
			if (com.isConnectComponent(component)) {
				coms.add(com);
			}
		}
		return coms;
	}

	/**
	 * 保存到磁盘
	 * @throws IOException
	 */
	public void save() throws IOException {
		ConfigFileParser.write(file, this);
	}

	/**
	 * 根据连接ID，找到连接对象
	 * @param id
	 * @return
	 */
	public Connect findConnectById(String id) {
		if (id == null) return null;
		Connect connect = null;
		for (Connect conn : connects) {
			if (id.equals(conn.getId())) {
				connect = conn;
				break;
			}
		}
		return connect;
	}

	/**
	 * 根据元件ID，找到元件对象
	 * @param id
	 * @return
	 */
	public BaseComponent findComponentById(String id) {
		if (id == null) return null;
		BaseComponent component = null;
		for (BaseComponent comp : components) {
			if (id.equals(comp.getId())) {
				component = comp;
				break;
			}
		}
		return component;
	}

}
